import java.util.ArrayList;

public class ChessBoard {

    private final int boardLength = 8;
    private final Piece[][] chessBoard = new Piece[boardLength][boardLength];

    private boolean check_WHITE;
    private boolean check_BLACK;

    private Piece currentCapturedPiece;
    private Color inCheck;

    private ArrayList<Coordinate> enemyPieceCoords;

    
    public ChessBoard() {
	currentCapturedPiece = null;
	inCheck = null;
	enemyPieceCoords = new ArrayList<Coordinate>();
	populate();
    }


    public boolean move( Color playerColor, int x1, int y1, int x2, int y2 ) {
	if( !legalLoc(x1) ||
	    !legalLoc(x2) ||
	    !legalLoc(y1) ||
	    !legalLoc(y2) ) { return false; }

	enemyPieceCoords.clear();
	//Is this playerColor in check? If so the King must be moved.
	if(false) {
	    //TODO
	}

	//Check that FromLoc has a piece
	if( chessBoard[x1][y1] == null ) { 
	    //System.err.println("\n1");
	    return false;
	} else if( chessBoard[x1][y1].color() != playerColor ) {
	    //System.err.println("\n2");
	    return false;
	}
	
	//Check that ToLoc doesn't have a Piece of the same Color
	if( chessBoard[x2][y2] != null ) {
	    if( chessBoard[x2][y2].color() == chessBoard[x1][y1].color() ) {
		//System.err.println("\n3");
		return false;
	    }
	}



	//Check that the movement is valid for the Piece
	boolean legalMove = true;
	boolean pawnFlag = false;
	if( !chessBoard[x1][y1].legalMove(x1,y1,x2,y2) ) { 
	    legalMove = false;
	    if( isPawn(chessBoard[x1][y1]) ) {
		pawnFlag = true;
	    }
	}

	/* Special situations */
	//Attacking pawn?  Pawn double-hop?
	if( pawnFlag ) {  
	    if( isPawnAttackMove(chessBoard[x1][y1].color(),x1,y1,x2,y2) ||
		isPawnDoubleHop(chessBoard[x1][y1].color(),x1,y1,x2,y2) ) {
		legalMove = true;
	    }
	}
	
	//Castling?
	if( castling(chessBoard[x1][y1].color(),x1,y1,x2,y2) ) {
	    return true;         //if it is castling, board changes will occur
	                         //in the private method
	}


	if( !legalMove ) {
	    return false;
	}




	//Did this player just move himself into check?  If so, return false
	//TODO


	currentCapturedPiece = chessBoard[x2][y2];
	
	chessBoard[x2][y2] = chessBoard[x1][y1];
	chessBoard[x2][y2].movesPlusOne();
	chessBoard[x1][y1] = null;
	
	return true;
    }


    public Piece getCapturedPiece() {
	return currentCapturedPiece;
    }

    


    private void populate() {

	for( int y = 0; y < boardLength; y++ ) {
	    chessBoard[1][y] = new Pawn(Color.WHITE);
	    chessBoard[6][y] = new Pawn(Color.BLACK);
	}

	chessBoard[0][0] = new Rook(Color.WHITE);
	chessBoard[0][1] = new Knight(Color.WHITE);
	chessBoard[0][2] = new Bishop(Color.WHITE);
	chessBoard[0][3] = new Queen(Color.WHITE);
	chessBoard[0][4] = new King(Color.WHITE);
	chessBoard[0][5] = new Bishop(Color.WHITE);
	chessBoard[0][6] = new Knight(Color.WHITE);
	chessBoard[0][7] = new Rook(Color.WHITE);

	chessBoard[7][0] = new Rook(Color.BLACK);
	chessBoard[7][1] = new Knight(Color.BLACK);
	chessBoard[7][2] = new Bishop(Color.BLACK);
	chessBoard[7][3] = new Queen(Color.BLACK);
	chessBoard[7][4] = new King(Color.BLACK);
	chessBoard[7][5] = new Bishop(Color.BLACK);
	chessBoard[7][6] = new Knight(Color.BLACK);
	chessBoard[7][7] = new Rook(Color.BLACK);
    }


    private boolean legalLoc( int x ) {
	return ( x >= 0 && x < boardLength );
    }

    private boolean isPawn( Piece piece ) {
	return piece.getClass().getName().equals("Pawn");
    }

    private boolean isPawnDoubleHop( Color c, int x1, int y1, int x2, int y2 ) {
	if( c == Color.WHITE ) {
	    if( (x1 == 1) && (x2 == 3) && (y2 == y1) ) {
		return true;
	    }
	} else {
	    if( (x1 == 6) && (x2 == 4) && (y2 == y1) ) {
		return true;
	    }
	}
	return false;
    }
    
    private boolean isPawnAttackMove( Color c, int x1, int y1, int x2, int y2 ) {
	boolean valid = false;
	if( c == Color.WHITE ) {
	    if( chessBoard[x2][y2] == null ) {
		return false;
	    }
	    if( ( (y2 == (y1+1)) || (y2 == (y1-1)) ) && ( x2 == (x1+1) ) &&
		( chessBoard[x2][y2].color() == Color.BLACK ) ) {
		valid = true;
	    } else {
		valid = false;
	    }
	} else {
	    if( chessBoard[x2][y2] == null ) {
		return false;
	    }
	    if( ( (y2 == (y1+1)) || (y2 == (y1-1)) ) && ( x2 == (x1-1) ) &&
		( chessBoard[x2][y2].color() == Color.WHITE ) ) {
		valid = true;
	    } else {
		valid = false;
	    }
	}
	return valid;
    }





    private boolean castling( Color c, int x1, int y1, int x2, int y2 ) {
	boolean valid = false;
	if( c == Color.WHITE ) {
	    if( (x1 == 0) && (y1 == 4) ) {
		if( (x2 == 0) && (y2 == 2) ) {
		    if( chessBoard[0][1] == null &&
			chessBoard[0][2] == null &&
			chessBoard[0][3] == null ) {
			if( chessBoard[0][0].getClass().getName().equals("Rook") && chessBoard[0][4].getClass().getName().equals("King") ) {
			    if( chessBoard[0][0].moveCount() == 0 &&
				chessBoard[0][4].moveCount() == 0 ) {
				chessBoard[0][2] = chessBoard[0][4];
				chessBoard[0][4] = null;
				chessBoard[0][3] = chessBoard[0][0];
				chessBoard[0][0] = null;
				chessBoard[0][2].movesPlusOne();
				chessBoard[0][3].movesPlusOne();
				currentCapturedPiece = null;
				return true;
			    }
			}
		    }
		} else if( (x2 == 0) && (y2 == 6) ) {
		    if( chessBoard[0][5] == null &&
			chessBoard[0][6] == null ) {
			if( chessBoard[0][7].getClass().getName().equals("Rook") && chessBoard[0][4].getClass().getName().equals("King") ) {
			    if( chessBoard[0][7].moveCount() == 0 &&
				chessBoard[0][4].moveCount() == 0 ) {
				chessBoard[0][6] = chessBoard[0][4];
				chessBoard[0][4] = null;
				chessBoard[0][5] = chessBoard[0][7];
				chessBoard[0][7] = null;
				chessBoard[0][6].movesPlusOne();
				chessBoard[0][5].movesPlusOne();
				currentCapturedPiece = null;
				return true;
			    }
			}
		    }
		}
	    }
	} else {
	    if( (x1 == 7) && (y1 == 4) ) {
		if( (x2 == 7) && (y2 == 2) ) {
		    if( chessBoard[7][1] == null &&
			chessBoard[7][2] == null &&
			chessBoard[7][3] == null ) {
			if( chessBoard[7][0].getClass().getName().equals("Rook") && chessBoard[7][4].getClass().getName().equals("King") ) {
			    if( chessBoard[7][0].moveCount() == 0 &&
				chessBoard[7][4].moveCount() == 0 ) {
				chessBoard[7][2] = chessBoard[7][4];
				chessBoard[7][4] = null;
				chessBoard[7][3] = chessBoard[7][0];
				chessBoard[7][0] = null;
				chessBoard[7][2].movesPlusOne();
				chessBoard[7][3].movesPlusOne();
				currentCapturedPiece = null;
				return true;
			    }
			}
		    }
		} else if( (x2 == 7) && (y2 == 6) ) {
		    if( chessBoard[7][5] == null &&
			chessBoard[7][6] == null ) {
			if( chessBoard[7][7].getClass().getName().equals("Rook") && chessBoard[7][4].getClass().getName().equals("King") ) {
			    if( chessBoard[7][7].moveCount() == 0 &&
				chessBoard[7][4].moveCount() == 0 ) {
				chessBoard[7][6] = chessBoard[7][4];
				chessBoard[7][4] = null;
				chessBoard[7][5] = chessBoard[7][7];
				chessBoard[7][7] = null;
				chessBoard[7][6].movesPlusOne();
				chessBoard[7][5].movesPlusOne();
				currentCapturedPiece = null;
				return true;
			    }
			}
		    }
		}
	    }
	}
	return false;
    }



    
    private boolean inCheck( Color playerColor ) {

	//return true if the player is in check
	//invoke after the opponent's move in the move method
	//if true, set the inCheck variable to playerColor
	//also use to make sure that a player can't move himself into check
	Color otherPlayer = null;
	if( playerColor == Color.WHITE ) {
	    otherPlayer = Color.BLACK;
	} else {
	    otherPlayer = Color.WHITE;
	}
	for( int x = 0; x < boardLength; x++ ) {
	    for( int y = 0; y < boardLength; y++ ) {
		if( chessBoard[x][y] != null ) {
		    if( chessBoard[x][y].color() == otherPlayer ) {
			enemyPieceCoords.add( new Coordinate(x,y) );
		    }
		}
	    }
	}
	for( int p = 0; p < enemyPieceCoords.size(); p++ ) {
	    int x1 = enemyPieceCoords.get(p).x();
	    int y1 = enemyPieceCoords.get(p).y();
	}
	return false;
    }


    public void printBoard() {
	System.out.println("\n");
	for( int x = boardLength-1; x >= 0; x-- ) {
	    System.out.print(x+1 + "\t");
	    for( int y = 0; y < boardLength; y++ ) {
		if( chessBoard[x][y] == null ) {
		    System.out.print("~" + "\t");
		} else {
		    System.out.print(chessBoard[x][y].name() + " \t");
		}
	    }
	    System.out.println("\n");
	}
	System.out.println();
	System.out.print("\t");
	for( int i = 0; i < boardLength; i++ ) {
	    System.out.print((char)(i+97) + "\t ");
	}
	System.out.println("\n");
    }
}
